#ifndef DAT_H
#define DAT_H
#include <iostream>
#include <vector>
#include <cmath>
#include <random>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <map>

#define ACTION_CNT 10000
#define MAX_WORKBENCH_CNT 50
#define ROBOT_CNT 4
#define LOCATION_LIMIT 28

using namespace std;

struct Location
{
    int x, y;
    bool operator==(const Location &a)
    {
        return abs(x - a.x) < LOCATION_LIMIT && abs(y - a.y) < LOCATION_LIMIT;
    }
};

struct Workbench
{
    Location loc;            // 工作台位置
    int type,                //  工作台类型
        remain_time,         // 剩余生产时间
        raw_material_status, // 原理格状态
        output_status;       // 产出格状态
} workbench_list[MAX_WORKBENCH_CNT];

struct SingleAction
{
    int workbench_start, workbench_end,
        load_type, // 运载的货物
        bar,       // 执行所需金额
        sell,      // 卖出价格
        time,      // 执行时间
        gain;      // 预期获得收益
};
vector<SingleAction> actions;
vector<vector<SingleAction>::iterator> available_action;

struct Robot
{
    int cur_workbench_id, // 当前所处工作台
        load_type;        // 当前所负载物品类型
    vector<SingleAction>::iterator cur_action;
    Location loc, expect_loc;
    double w,       // 角速度
        face_angle; //  朝向的角度
} robot_list[ROBOT_CNT];

int init_action_workbench_end[][4] = {
    {0},
    {3, 4, 5, 9}, // 1
    {3, 4, 6, 9}, // 2
    {3, 5, 6, 9}, // 3
    {2, 7, 9},    // 4
    {2, 7, 9},    // 5
    {2, 7, 9},    // 6
    {2, 8, 9},    // 7
};
int init_remain_time[] = {0, 50, 50, 50, -1, -1, -1, -1, -1, -1};
int init_action_bar[] = {0, 3000, 4400, 5800, 15400, 17200, 19200, 76000};
int init_action_sell[] = {0, 6000, 7600, 9200, 22500, 25000, 27500, 105000};
int money = 200000;
int workben_cnt;
const double PI = acos(-1),
             PI_DIV_2 = acos(0),
             PI2 = 2 * PI,
             ANGLE_EPS = 1e-3;

inline int calculateTimeBetweenLoc(Location a, Location b)
{
    int dx = a.x - b.x;
    int dy = a.y - b.y;
    double dis = sqrt(dx * dx + dy * dy);
    return dis / 12;
}

inline double getAngleBetweenLoc(Location source, Location dest)
{
    if (source.x == dest.x)
    {
        if (dest.y - source.y > 0)
            return PI;
        else
            return -PI;
    }
    double dx = dest.x - source.x,
           dy = dest.y - source.y,
           r = 0;
    double ang = atan(dy / dx);
    if (dx < 0)
    {
        if (dy > 0)
            return PI + ang;
        return ang - PI;
    }
    return ang;
}

void filterAvailableAction(Location rob_loc)
{
    available_action.clear();
    for (auto i = actions.begin(); i < actions.end(); i++)
    {
        Workbench &workbench_start = workbench_list[i->workbench_start],
                  &workbench_end = workbench_list[i->workbench_end];
        if (money < i->bar)
            continue;
        // 检查输出端是否满足要求
        if (workbench_start.output_status == 0)
        {
            if (workbench_start.remain_time < 0 || calculateTimeBetweenLoc(rob_loc, workbench_start.loc) < workbench_start.remain_time)
                continue;
        }
        // 检查输入端
        if (workbench_end.raw_material_status & (1 << i->load_type))
        {
            continue;
        }
        // 检测与其他机器人任务是否冲突
        bool ok = true;
        for (auto &rob : robot_list)
        {
            if (rob.cur_action == actions.end())
                continue;
            if (rob.cur_action->workbench_start == i->workbench_start || rob.cur_action->workbench_end == i->workbench_end)
            {
                ok = false;
                break;
            }
        }
        if (ok)
            available_action.push_back(i);
    }
}

void filterAvailableAction()
{
    map<int, vector<vector<SingleAction>::iterator>> available_action_tmp;
    available_action.clear();
    for (auto i = actions.begin(); i < actions.end(); i++)
    {
        Workbench &workbench_start = workbench_list[i->workbench_start],
                  &workbench_end = workbench_list[i->workbench_end];
        if (money < i->bar)
            continue;
        // 检查输出端是否满足要求
        if (workbench_start.output_status == 0)
        {
            if (workbench_start.remain_time < 0 || 100 < workbench_start.remain_time)
                continue;
        }
        // 检查输入端
        if (workbench_end.raw_material_status & (1 << i->load_type))
        {
            continue;
        }
        // 检测与其他机器人任务是否冲突
        bool ok = true;
        for (auto &rob : robot_list)
        {
            if (rob.cur_action == actions.end())
                continue;
            if (rob.cur_action->workbench_start == i->workbench_start || rob.cur_action->workbench_end == i->workbench_end)
            {
                ok = false;
                break;
            }
        }
        if (ok)
            available_action_tmp[i->workbench_start].push_back(i);
    }
    for (int i = 0; i < workben_cnt; i++)
    {
        if (available_action_tmp.count(i) == 0)
            continue;
        vector<SingleAction>::iterator best = available_action_tmp[i][0];
        int short_time = best->time;
        for (int j = 1; j < available_action_tmp[i].size(); j++)
        {
            if (short_time > available_action_tmp[i][j]->time)
            {
                short_time = available_action_tmp[i][j]->time;
                best = available_action_tmp[i][j];
            }
        }
        available_action.push_back(best);
    }
}
#endif // !DAT_H
